﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PROJECT_BOMBER.BLL
{
    public class Level : ElementPhysique
    {

        #region Constructeur
        //List<LevelAnimation> _listframe;

        //public List<LevelAnimation> Listframe
        //{
        //    get { return _listframe; }
        //    set { _listframe = value; }
        //}

        public Level() : this(0, 0) { }

        public Level(int x, int y)
            : base(x, y)
        {

            //Listframe = new List<LevelAnimation>();
            Width = 0;
            Height = 0;
        }

        #endregion

        #region AnimationSprite

        public List<LevelBloc> Listframe = new List<LevelBloc>();

        public List<LevelBloc> Lvl1 = new List<LevelBloc>();

        public List<LevelBloc> Lvl2 = new List<LevelBloc>();

        public List<LevelBloc> Lvl3 = new List<LevelBloc>();


        /// <summary>
        /// Regroupement des initialize AnimationSprite
        /// </summary>
        public void InitializeAnimation()
        {
            int i = 0;
            foreach (LevelBloc anim in Listframe)
            {
                anim.Base().Initialize();
                anim.Background().Initialize();
                anim.Foreground().Initialize();


                foreach (var item in anim.listElement)
                {
                    item.InitializeAnimations();

                }
                i++;
            }

        }

        /// <summary>
        ///  Regroupement des chargements des AnimationSprite
        /// </summary>
        /// <param name="spriteBatch"></param>
        public new void LoadAnimations(SpriteBatch spriteBatch)
        {
            foreach (LevelBloc anim in Listframe)
            {
                anim.Base().LoadContent(spriteBatch);
                anim.Background().LoadContent(spriteBatch);
                anim.Foreground().LoadContent(spriteBatch);

                foreach (var item in anim.listElement)
                {
                    item.LoadAnimations(Globals.SpriteBatch);
                }
            }
        }

        /// <summary>
        /// On dessine les AnimationSprite
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="type"></param>
        public void DrawAnimation(GameTime gameTime, int type)
        {
            if (type == 0)
            {
                foreach (LevelBloc anim in Listframe)
                {
                    anim.Background().Draw();
                }
            }
            else if (type == 1)
            {
                foreach (LevelBloc anim in Listframe)
                {
                    anim.Base().Draw();

                    foreach (var item in anim.listElement)
                    {
                        if (item.CurrentAnimation != null)
                        {
                            item.DrawAnimation();
                        }
                    }
                }
            }

            else if (type == 2)
            {
                foreach (LevelBloc anim in Listframe)
                {
                    anim.Foreground().Draw();
                }
            }
        }

        #endregion

        #region Update

        /// <summary>
        /// Regroupement des updates des AnimationSprite
        /// </summary>
        /// <param name="gametime"></param>
        public void Update()
        {

            Case = new Rectangle((int)Position.X, (int)Position.Y, Width, Height);

            int posX = 0;

            foreach (LevelBloc anim in Listframe)
            {
                anim.Base().Update(Case.X + posX, Case.Y, new Vector2(0, 0), 1, false);
                anim.Background().Update(Case.X + posX, Case.Y, new Vector2(0, 0), 1, false);
                anim.Foreground().Update(Case.X + posX, Case.Y, new Vector2(0, 0), 1, false);

                foreach (var item in anim.listElement)
                {
                    Vector2 pos = new Vector2(item.Positionbase.X + posX, item.Positionbase.Y);
                    item.Update(Globals.GameTime, Globals.GDM, Globals.Camera, this, pos);

                }

                posX += anim.Base().Definition.FrameSize.X;
            }

        }
        #endregion

        #region Collision

        // Obsolète
        public void CollisionObjet(ElementMove charater)
        {
            Collision.GroundCollision(charater, this);
        }

        #endregion

        // Indescriptible
        public new int[] CalcIntersect(ElementMove element1)
        {

            int[] valuereturn = new int[4];

            if (element1.GetType() == new Character(0, 0).GetType())
            {
                Character element = element1 as Character;

                #region character

                for (int i = 0; i < 4; i++)
                {
                    valuereturn[i] = 0;
                }

                int posX = 0;

                foreach (LevelBloc animation in Listframe)
                {
                    Rectangle Casetest = new Rectangle(
                        posX,
                        -animation.Base().Definition.FrameSize.Y,
                        animation.Base().Sprite.Bounds.Width,
                        animation.Base().Sprite.Bounds.Height);

                    if (Casetest.Intersects(element.Case) == true)
                    {

                        #region Rectangles du personnage dont les coordonnées X Y sont calculés par rapport a l'image du perso

                        Rectangle[] rectangleA = new Rectangle[4];

                        rectangleA[0] = new Rectangle(0, 0, element.Width / 2, element.Height / 2);
                        rectangleA[1] = new Rectangle(element.Width / 2, 0, element.Width / 2, element.Height / 2);
                        rectangleA[2] = new Rectangle(element.Width / 2, element.Height / 2, element.Width / 2, element.Height / 2);
                        rectangleA[3] = new Rectangle(0, element.Height / 2, element.Width / 2, element.Height / 2);

                        #endregion

                        #region Rectangles du personnage dont les coordonnées X Y sont calculés par rapport à la fenetre de jeu

                        Rectangle[] rectangleF = new Rectangle[4];

                        rectangleF[0] = new Rectangle((int)element.Position.X, (int)element.Position.Y, element.Width / 2, element.Height / 2);
                        rectangleF[1] = new Rectangle((int)element.Position.X + element.Width / 2, (int)element.Position.Y, element.Width / 2, element.Height / 2);
                        rectangleF[2] = new Rectangle((int)element.Position.X + element.Width / 2, (int)element.Position.Y + element.Height / 2, element.Width / 2, element.Height / 2);
                        rectangleF[3] = new Rectangle((int)element.Position.X, (int)element.Position.Y + element.Height / 2, element.Width / 2, element.Height / 2);

                        #endregion


                        #region calcul des limites de taille des rectangles du niveau par rapport a la zone étudiée

                        int bottomY = Math.Max(-(int)(element.Position.Y + element.Height), 0);
                        int topY = Math.Min(-(int)element.Position.Y, animation.Base().Sprite.Height);
                        int leftX = Math.Max((int)element.Position.X, posX);
                        int rightX = Math.Min((int)element.Position.X + element.Width, posX + animation.Base().Sprite.Width);

                        #endregion

                        #region Rectangles du niveau dont les coordonnées X Y sont calculés par rapport a l'image du perso et limitée à la zone concernée

                        Rectangle rectangleB = new Rectangle(leftX, (int)element.Position.Y, rightX - leftX, topY - bottomY);
                        Rectangle[] rectangleD = new Rectangle[4];

                        rectangleD[0] = new Rectangle(rectangleB.X, rectangleB.Y, rectangleB.Width / 2, rectangleB.Height / 2);
                        rectangleD[1] = new Rectangle(rectangleB.X + rectangleB.Width / 2, rectangleB.Y, rectangleB.Width / 2, rectangleB.Height / 2);
                        rectangleD[2] = new Rectangle(rectangleB.X + rectangleB.Width / 2, rectangleB.Y + rectangleB.Height / 2, rectangleB.Width / 2, rectangleB.Height / 2);
                        rectangleD[3] = new Rectangle(rectangleB.X, rectangleB.Y + rectangleB.Height / 2, rectangleB.Width / 2, rectangleB.Height / 2);

                        #endregion

                        #region Rectangles du niveau dont les coordonnées X Y sont calculés par rapport à la fenetre de jeu et limitée à la zone concernée

                        Rectangle rectangleC = new Rectangle(leftX - posX, animation.Base().Sprite.Height - topY - animation.Base().Definition.FrameSize.Y + animation.Base().Sprite.Height, rightX - leftX, topY - bottomY);
                        Rectangle[] rectangleE = new Rectangle[4];

                        rectangleE[0] = new Rectangle(rectangleC.X, rectangleC.Y, rectangleC.Width / 2, rectangleC.Height / 2);
                        rectangleE[1] = new Rectangle(rectangleC.X + rectangleC.Width / 2, rectangleC.Y, rectangleC.Width / 2, rectangleC.Height / 2);
                        rectangleE[2] = new Rectangle(rectangleC.X + rectangleC.Width / 2, rectangleC.Y + rectangleC.Height / 2, rectangleC.Width / 2, rectangleC.Height / 2);
                        rectangleE[3] = new Rectangle(rectangleC.X, rectangleC.Y + rectangleC.Height / 2, rectangleC.Width / 2, rectangleC.Height / 2);

                        #endregion


                        #region comparaison dans les limites des paires de rectangles chaque pixel et incrementant le compteur [valuereturn] quand 2 pixels ne sont pas transparent

                        for (int i = 0; i < 4; i++)
                        {
                            // mise en tableau des pixels du perso
                            Color[] dataA = new Color[rectangleA[i].Width * rectangleA[i].Height];
                            element.CurrentAnimation.Sprite.GetData(0, rectangleA[i], dataA, 0, rectangleA[i].Width * rectangleA[i].Height);


                            Color[] dataB = new Color[rectangleD[i].Width * rectangleD[i].Height];

                            if (rectangleD[i].Width * rectangleD[i].Height > 0)
                            {
                                //mise en tableau des pixels du niveau
                                animation.Base().Sprite.GetData(0, rectangleE[i], dataB, 0, rectangleD[i].Width * rectangleD[i].Height);

                                // determine limites a étudier
                                int top = Math.Max(rectangleF[i].Top, rectangleD[i].Top);
                                int bottom = Math.Min(rectangleF[i].Bottom, rectangleD[i].Bottom);
                                int left = Math.Max(rectangleF[i].Left, rectangleD[i].Left);
                                int right = Math.Min(rectangleF[i].Right, rectangleD[i].Right);

                                #region comparaison des pixels
                                for (int y = bottom - 1; y >= top; y--)
                                {
                                    for (int x = left; x < right; x++)
                                    {
                                        Color colorA = dataA[(x - rectangleF[i].Left) +
                                                             (y - rectangleF[i].Top) *
                                                             rectangleF[i].Width];
                                        Color colorB = dataB[(x - rectangleD[i].Left) +
                                                             (y - rectangleD[i].Top) *
                                                             rectangleD[i].Width];
                                        if (colorA.A != 0 && colorB.A != 0)
                                        {
                                            valuereturn[i]++;
                                        }
                                    }
                                }
                                #endregion
                            }

                        }

                        #endregion

                    }
                    posX += animation.Base().Sprite.Width;
                }
                return valuereturn;

                #endregion

            }

            return valuereturn;


        }

        // Indescriptible
        public override double AnglePX(ElementMove element1)
        {
            Character element = element1 as Character;

            #region character

            int[] valuereturn = new int[2];
            int imgX = 0;

            for (int i = 0; i < 2; i++)
            {
                valuereturn[i] = 0;
            }

            #region determine pixels de pente
            foreach (LevelBloc animation in Listframe)
            {
                imgX++;

                if (new Rectangle(animation.Base().Definition.FrameSize.X * imgX - animation.Base().Sprite.Width, -animation.Base().Definition.FrameSize.Y, animation.Base().Sprite.Bounds.Width, animation.Base().Sprite.Bounds.Height).Intersects(element.Case) == true && element.Position.Y - element.Height > 0)
                {

                    #region Rectangles du personnage dont les coordonnées X Y sont calculés par rapport a l'image du perso

                    Rectangle[] rectangleA = new Rectangle[4];

                    rectangleA[0] = new Rectangle(0, element.Height / 2, 1, element.Height);
                    rectangleA[1] = new Rectangle(element.Width - 1, element.Height / 2, 1, element.Height);


                    #endregion

                    #region Rectangles du personnage dont les coordonnées X Y sont calculés par rapport à la fenetre de jeu

                    Rectangle[] rectangleF = new Rectangle[4];

                    rectangleF[0] = new Rectangle((int)element.Position.X, (int)element.Position.Y + element.Height / 2, 1, element.Height);
                    rectangleF[1] = new Rectangle((int)element.Position.X + element.Width - 1, (int)element.Position.Y + element.Height / 2, 1, element.Height);

                    #endregion


                    #region calcul des limites de taille des rectangles du niveau par rapport a la zone étudiée

                    int bottomY = Math.Max(-(int)(element.Position.Y + element.Height), 0);
                    int topY = Math.Min(-(int)element.Position.Y, animation.Base().Sprite.Height);
                    int leftX = Math.Max((int)element.Position.X, animation.Base().Definition.FrameSize.X * imgX - animation.Base().Sprite.Width);
                    int rightX = Math.Min((int)element.Position.X + element.Width, animation.Base().Sprite.Width + animation.Base().Definition.FrameSize.X * imgX - animation.Base().Sprite.Width);

                    #endregion

                    #region Rectangles du niveau dont les coordonnées X Y sont calculés par rapport a l'image du perso et limitée à la zone concernée

                    Rectangle rectangleB = new Rectangle(leftX, (int)element.Position.Y, rightX - leftX, topY - bottomY);
                    Rectangle[] rectangleD = new Rectangle[4];

                    rectangleD[0] = new Rectangle(rectangleB.X, rectangleB.Y + rectangleB.Height / 2, 1, rectangleB.Height);
                    rectangleD[1] = new Rectangle(rectangleB.X + rectangleB.Width - 1, rectangleB.Y + rectangleB.Height / 2, 1, rectangleB.Height);

                    #endregion

                    #region Rectangles du niveau dont les coordonnées X Y sont calculés par rapport à la fenetre de jeu et limitée à la zone concernée

                    Rectangle rectangleC = new Rectangle(leftX - animation.Base().Definition.FrameSize.X * imgX + animation.Base().Sprite.Width,
                                                            animation.Base().Sprite.Height - topY - animation.Base().Definition.FrameSize.Y + animation.Base().Sprite.Height,
                                                            rightX - leftX,
                                                            topY - bottomY);
                    Rectangle[] rectangleE = new Rectangle[4];

                    rectangleE[0] = new Rectangle(rectangleC.X, rectangleC.Y + rectangleC.Height / 2, 1, rectangleC.Height);
                    rectangleE[1] = new Rectangle(rectangleC.X + rectangleC.Width - 1, rectangleC.Y + rectangleC.Height / 2, 1, rectangleC.Height);

                    #endregion


                    #region comparaison dans les limites des paires de rectangles chaque pixel et incrementant le compteur [valuereturn] quand 2 pixels ne sont pas transparent

                    for (int i = 0; i < 2; i++)
                    {
                        Color[] dataB = new Color[rectangleD[i].Width * rectangleD[i].Height];

                        if (rectangleD[i].Width * rectangleD[i].Height > 0)
                        {
                            //mise en tableau des pixels du niveau
                            animation.Base().Sprite.GetData(0, rectangleE[i], dataB, 0, rectangleD[i].Width * rectangleD[i].Height);

                            // determine limites a étudier
                            int top = rectangleD[i].Top;
                            int bottom = rectangleD[i].Bottom;
                            int left = rectangleD[i].Left;
                            int right = rectangleD[i].Right;

                            #region comparaison des pixels
                            for (int y = bottom - 1; y >= top; y--)
                            {
                                for (int x = left; x < right; x++)
                                {
                                    Color colorB = dataB[(x - rectangleD[i].Left) +
                                                         (y - rectangleD[i].Top) *
                                                         rectangleD[i].Width];
                                    if (colorB.A != 0)
                                    {
                                        valuereturn[i]++;
                                    }
                                }
                            }
                            #endregion
                        }

                    }
                    #endregion
                }

            }
            #endregion

            #region calcul de l'angle de pente
            if ((valuereturn[0] > element.Height / 2 || valuereturn[1] > element.Height / 2) && valuereturn[0] > 0 && valuereturn[1] > 0)
            {
                int H = valuereturn[0] - valuereturn[1];
                int L = element1.Width;
                double Angle = Math.Atan((float)(-H) / (float)L) * 180 / Math.PI;
                if (Angle < 20)
                {
                    return Angle;
                }
                else
                {
                    return 0;
                }
            }
            else
            {
                return 0;
            }
            #endregion


            #endregion
        }

        /// <summary>
        /// Add frames to the list
        /// </summary>
        /// <param name="img1"></param>
        /// <param name="img2"></param>
        /// <param name="img3"></param>
        /// <param name="game"></param>
        /// 

        public void addFrame(AnimationDefinition img1, AnimationDefinition img2, AnimationDefinition img3, Game game)
        {
            // Agrandit le niveau en fonction de la portion ajoutée

            Position = new Vector2(Position.X, -img1.FrameSize.Y);

            LevelBloc anim = new LevelBloc(0, game);

            // Attribut l'image aux Background, Base et Foreground
            anim.Background(img2, game);
            anim.Base(img1, game);
            anim.Foreground(img3, game);

            Width += anim.Base().Definition.FrameSize.X;
            Height = anim.Base().Definition.FrameSize.Y;


            Listframe.Add(anim);

        }



        public void addFrame(AnimationDefinition img1, AnimationDefinition img2, AnimationDefinition img3, Game game, int previouslvl, int nextlvl)
        {
            // Agrandit le niveau en fonction de la portion ajoutée

            Position = new Vector2(Position.X, -img1.FrameSize.Y);

            LevelBloc anim = new LevelBloc(nextlvl, game);

            // Attribut l'image aux Background, Base et Foreground
            anim.Background(img2, game);
            anim.Base(img1, game);
            anim.Foreground(img3, game);



            // Ajoute à la le LevelAnimation à la liste
            if (previouslvl == 1)
            {
                Lvl1.Add(anim);
            }
            else if (previouslvl == 2)
            {
                Lvl2.Add(anim);
            }
            else if (previouslvl == 3)
            {
                Lvl3.Add(anim);
            }

        }
        /// <summary>
        /// On génère aléatoirement le niveau avec nos trois listes
        /// </summary>
        public void GenerateLevel(int nbImage)
        {
            Random random = new Random();


            var totalImage = 200;

            int maxImage = 100;


            // le nombre de frame du niveau ne peux dépasser 100
            totalImage = Math.Min(maxImage, nbImage);

            Listframe.Clear();

            Listframe.Add(Lvl1[random.Next(0, Lvl1.Count)]);

            Width += Listframe[0].Base().Definition.FrameSize.X;

            for (int i = 1; i < totalImage; i++)
            {


                LevelBloc image = Listframe[i - 1];

                LevelBloc RandomLvl = null;
                int level = image.Nextlevel;

                switch (level)
                {
                    case 1:

                        RandomLvl = (LevelBloc)Lvl1[random.Next(0, Lvl1.Count)].Clone();
                        break;

                    case 2:
                        RandomLvl = (LevelBloc)Lvl2[random.Next(0, Lvl2.Count)].Clone();
                        break;

                    case 3:
                        RandomLvl = (LevelBloc)Lvl3[random.Next(0, Lvl3.Count)].Clone();
                        break;
                }

                Width += RandomLvl.Base().Definition.FrameSize.X;
                Height = RandomLvl.Base().Definition.FrameSize.Y;

                Listframe.Add(RandomLvl);
            }


        }
        /* public void getrefeRandomefz zef Frame( List<LevelAnimation> list)
         {
            
         }*/
    }
}
